package com.ai.zuochengyun.phase01.class01;

import java.util.*;

public class Code16_EveryStepShowBossV2 {

    public static List<List<Integer>> topK(int[] arr, boolean[] op, int k) {
        List<List<Integer>> ans = new ArrayList<>();
        WhoIsWinner obj = new WhoIsWinner(k);
        for (int i = 0; i < arr.length; i++) {
            obj.operate(arr[i], op[i]);
            ans.add(obj.getDaddies());
        }
        return ans;
    }

    private static class WhoIsWinner {
        private final Map<Integer, Code16_Customer> customers;

        private final Code15_HeapGreater<Code16_Customer> candidateHeap;

        private final Code15_HeapGreater<Code16_Customer> winnerHeap;

        private final int daddyLimit;

        public WhoIsWinner(int limit) {
            customers = new HashMap<>();
            candidateHeap = new Code15_HeapGreater<>(new Code16_Customer.CandidateComparator());
            winnerHeap = new Code15_HeapGreater<>(new Code16_Customer.WinnerComparator());
            daddyLimit = limit;
        }

        /**
         * 关键方法
         * @param no
         * @param buyOrRefund
         */
        public void operate(int no, boolean buyOrRefund) {
            // 顾客不存在，但发生了退货
            if (!customers.containsKey(no) && !buyOrRefund) {
                return;
            }

            // 购买了
            if (!customers.containsKey(no)) {
                customers.put(no, new Code16_Customer(no, 0, 0));
            }

            Code16_Customer customer = customers.get(no);
            if (buyOrRefund) {
                customer.buy++;
            } else {
                customer.buy--;
            }

            if (customer.buy <= 0) {
                customers.remove(no);
            }

            if (!candidateHeap.contains(customer) && !winnerHeap.contains(customer)) {
                // 候选区和得奖区都没有，表明你刚开始购买了一件商品
                customer.enterTime = System.currentTimeMillis();
                if (winnerHeap.size() < daddyLimit) {
                    winnerHeap.push(customer);
                } else {
                    candidateHeap.push(customer);
                }
            } else if (candidateHeap.contains(customer)) {
                // 如果在候选区
                if (customer.buy == 0) {
                    candidateHeap.remove(customer);
                } else {
                    candidateHeap.resign(customer);
                }
            } else {
                // 如果在得奖区
                if (customer.buy == 0) {
                    winnerHeap.remove(customer);
                } else {
                    winnerHeap.resign(customer);
                }
            }

            // 调整候选区和得奖区的元素
            move();
        }

        /**
         * 调整候选区和得奖区的元素
         */
        private void move() {
            // 候选区为空
            if (candidateHeap.isEmpty()) {
                return;
            }

            // 候选区不空
            if (winnerHeap.size() < daddyLimit) {
                // 得奖区不满
                // 将候选区从大到小排序的第一个元素加入到得奖区
                Code16_Customer customer= candidateHeap.pop();
                customer.enterTime = System.currentTimeMillis();
                winnerHeap.push(customer);
            } else {
                // 得奖区已满，替换
                if (candidateHeap.peek().buy > winnerHeap.peek().buy) {
                    // 将之前中奖区的选手从中奖区转移到候选区
                    // 将之前候选区的选手从候选区转移到中奖区
                    Code16_Customer degrade = winnerHeap.popTail();
                    degrade.enterTime = System.currentTimeMillis();

                    Code16_Customer upgrade = candidateHeap.pop();
                    upgrade.enterTime = degrade.enterTime;

                    winnerHeap.push(upgrade);
                    candidateHeap.push(degrade);
                }
            }
        }

        public List<Integer> getDaddies() {
            List<Integer> ans = new ArrayList<>();
            for (Code16_Customer customer : winnerHeap.getAllElements()) {
                ans.add(customer.id);
            }
            return ans;
        }
    }

    /**
     * 候选区排序规则
     */
    public static class CandidateComparator implements Comparator<Code16_Customer> {

        @Override
        public int compare(Code16_Customer o1, Code16_Customer o2) {
            // 购买越大的放前面，如果购买数相同，谁早谁在前。
            return o1.buy != o2.buy ? o2.buy - o1.buy : (int) (o1.enterTime - o2.enterTime);
        }
    }

    /**
     * 得奖区排序规则，因为要替换前面的元素
     */
    public static class DaddyComparator implements Comparator<Code16_Customer> {

        @Override
        public int compare(Code16_Customer o1, Code16_Customer o2) {
            // 购买越少的放前面，如果购买数相同，
            // 谁后买谁在后，因为前者先买但是目前并未发生新的购买，可能购买力没有后来的强，那么后面在替换的时候，优先替换掉最早购买的
            return o1.buy != o2.buy ? o1.buy - o2.buy : (int) (o1.enterTime - o2.enterTime);
        }
    }
}
